
import { _decorator, Component, Node, Sprite, ProgressBar, Label, log, find, TiledMap, Tween, Vec3 } from 'cc';
import { Attack } from './animation/Attack';
import { Message, MessageType, CommandType } from './framework/Message';
import { MessageBase } from './framework/MessageBase';
import { MessageCenter } from './framework/MessageCenter';
import { GameData } from './GameData';
import { Map } from './map/Map';
import { MiniMap } from './map/MiniMap';
import { Hero } from './player/Hero';
import { Item } from './player/Item';
import { Move } from './player/Move';
import { Pet } from './player/Pet';
import { UIManager } from './UIManager';
import { Utils } from './utils/Utils';
const { ccclass, property } = _decorator;

/**
 * Predefined variables
 * Name = BattleManager
 * DateTime = Sat Feb 05 2022 15:06:05 GMT+0800 (China Standard Time)
 * Author = vvc_zeng
 * FileBasename = BattleManager.ts
 * FileBasenameNoExtension = BattleManager
 * URL = db://assets/script/map/BattleManager.ts
 * ManualUrl = https://docs.cocos.com/creator/3.3/manual/zh/
 *
 */

@ccclass('BattleManager')
export class BattleManager extends MessageBase {
    static Instance: BattleManager = null;
    // buff 组件
    heroBuffNode: Node;
    pet0BuffNode: Node;
    pet1BuffNode: Node;
    monster0BuffNode: Node;
    onLoad() {
        super.onLoad()
        BattleManager.Instance = this;

        this.heroBuffNode = this.node.getChildByPath("Hero/Buff");
        this.pet0BuffNode = this.node.getChildByPath("Pet0/Buff");
        this.pet1BuffNode = this.node.getChildByPath("Pet1/Buff");
        this.monster0BuffNode = this.node.getChildByPath("Monster0/Buff");

        this.initData()
    }
    init() {
        this.messageType = MessageType.TYPE_BATTLE;
    }
    // 战斗结束时调用一下，清除战时数据
    initData() {
        this.heroStat = [];
        this.petStat = [];
        this.petId = [];
        this.monsterStat = [];
        this.mid = -1;

        this.attackQueue = [];
        this.heroBuff = [];
        this.petBuff = [];
        this.monsterBuff = []

        this.finished = false;
        this.tips = '';
    }
    ReveiveMessage(message: Message) {
        super.ReveiveMessage(message);
        if (message.Command == CommandType.COM_BATTLE_START) {
            this.battleHandler(message.Content);
        }
    }
    // battleStat 战斗时属性
    heroStat: number[];
    petStat: number[][];
    petId: number[];
    monsterStat: number[];
    mid: number;
    // 每个主回合结束时将要处理的buff {tag:'h',target:'m',...heroBuff}
    battleQueue = [];
    // 每一个主回合产生的攻击队列
    attackQueue = [];
    // 英雄身上的buff buff的总表id 剩余回合数 {id,turn}
    heroBuff = [];
    petBuff = [];
    monsterBuff = [];

    // mainTurn 战斗主回合
    mainTurn: number = 0;
    // 战斗结束标志位
    finished: boolean = false;
    // 伤害辅助信息 暴击、闪避
    tips: string = '';
    // buff 效果一览 21 正面 24 负面
    buffData = [
        {
            func: function (stat, tag, target, bq?) {
                if (Utils.getRandomRange(1, 10) < 4) {
                    bq.push({ tag, target, id: 31, turn: 1 });
                }
            }
        },
        {
            func: function (stat, tag, target, bq?) {
                bq.push({ tag, target, id: 38, turn: 3 });
            }
        },
        {
            func: function (stat, tag, target, bq?) {
                bq.push({ tag, target, id: 25, turn: 3 });
            }
        },
        {
            func: function (stat) {
                stat[2] *= 2;
            }
        },
        {
            func: function (stat, tag, target, bq?) {
                bq.push({ tag, target, id: 23, turn: 3 });
            }
        },
        {
            func: function (stat, tag, target, bq?) {
                bq.push({ tag, target, id: 24, turn: 3 });
            }
        },
        {
            func: function (stat) {
                stat[3] += 10;
            }
        },
        {
            func: function (stat) {
                stat[6] += 10;
            }
        },
        {
            func: function (stat, tag, target) {
                if (target == 'h') {
                    MessageCenter.SendCustomMessage(MessageType.TYPE_HERO, CommandType.COM_HERO_HP, -5)
                } else {
                    stat[0] -= 5;
                }
                stat[2] += 20;
            }
        },
        {
            func: function (stat) {
                stat[2] += 5;
                stat[6] += 10;
            }
        },
        {
            func: function (stat, tag, target, bq?) {
                bq.push({ tag, target, id: 33, turn: 3 });
            }
        },
        {
            func: function (stat) {
                for (let i = 2; i < stat.length; i++) {
                    stat[i] += 5;
                }
            }
        },
        {
            func: function (stat, tag, target, bq?) {
                bq.push({ tag, target, id: 30, turn: 1 });
            }
        },
        {
            func: function (stat, tag, target) {
                if (target == 'h') {
                    MessageCenter.SendCustomMessage(MessageType.TYPE_HERO, CommandType.COM_HERO_HP, 40)
                } else {
                    stat[0] += 40;
                }
            }
        },
        {
            func: function (stat, tag, target, bq?) {
                bq.push({ tag, target, id: 21, turn: 3 });
            }
        },
        {
            func: function (stat) {
                stat[7] += 20;
            }
        },
        {
            func: function (stat) {
                if (Utils.getRandomRange(1, 10) < 4) {
                    stat[2] *= 2;
                }
            }
        },
        {
            func: function (stat, tag, target) {
                if (target == 'h') {
                    MessageCenter.SendCustomMessage(MessageType.TYPE_HERO, CommandType.COM_HERO_HP, Hero.Instance.hp)
                } else {
                    stat[0] *= 2;
                }
            }
        },
        {
            func: function (stat) {
                stat[2] += Math.round(stat[0] / 5 + stat[3] / 4)
            }
        },
        {
            func: function (stat, tag, target, bq?) {
                if (Utils.getRandomRange(1, 10) < 4) {
                    bq.push({ tag, target, id: 37, turn: 1 });
                }
            }
        },
        {
            func: function (stat, tag, target) {
                if (target == 'h') {
                    MessageCenter.SendCustomMessage(MessageType.TYPE_HERO, CommandType.COM_HERO_HP, 20)
                    MessageCenter.SendCustomMessage(MessageType.TYPE_HERO, CommandType.COM_HERO_MP, 10)
                } else {
                    stat[0] += 20;
                    stat[1] += 10;
                }
                // 往下就是debuff
            }
        },
        {
            func: function (stat) {
                stat[6] -= 2;
            }
        },
        {
            func: function (stat) {
                stat[4] -= 2;
            }
        },
        {
            func: function (stat) {
                stat[3] -= 2;
            }
        },
        {
            func: function (stat, tag, target) {
                if (target == 'h') {
                    MessageCenter.SendCustomMessage(MessageType.TYPE_HERO, CommandType.COM_HERO_HP, -2)
                } else {
                    stat[0] -= 2;
                }
            }
        },
        {
            func: function (stat) {
                stat[5] -= 2;
            }
        },
        {
            func: function (stat) {
                stat[2] -= 2;
            }
        },
        {
            func: function (stat) {
                stat[2] += 4;
                stat[4] -= 2;
            }
        },
        {
            func: function (stat, tag, target) {
                if (target == 'h') {
                    MessageCenter.SendCustomMessage(MessageType.TYPE_HERO, CommandType.COM_HERO_MP, -2)
                } else {
                    stat[1] -= 2;
                }
            }
        },
        {
            func: function (stat, tag, target) {
                if (Utils.getRandomRange(1, 10) < 6) {
                    if (target == 'h') {
                        MessageCenter.SendCustomMessage(MessageType.TYPE_HERO, CommandType.COM_HERO_HP, -Math.round(stat[2] / 2))
                    } else {
                        stat[0] -= Math.round(stat[2] / 2)
                    }
                    stat[2] = 0
                }
            }
        },
        {
            func: function (stat, tag, target) {
                if (Utils.getRandomRange(1, 10) < 6) {
                    if (target == 'h') {
                        MessageCenter.SendCustomMessage(MessageType.TYPE_HERO, CommandType.COM_HERO_HP, - Math.round(stat[6] / 3))
                    } else {
                        stat[0] -= Math.round(stat[6] / 3)
                    }

                }
            }
        },
        {
            func: function (stat) {
                // 晕眩
                if (Utils.getRandomRange(1, 10) < 8) {
                    stat[3] -= 4
                    stat[2] = 0
                }
            }
        },
        {
            func: function (stat) {
                stat[6] += 4;
                stat[2] -= 2;
            }
        },
        {
            func: function (stat, tag, target) {
                if (target == 'h') {
                    MessageCenter.SendCustomMessage(MessageType.TYPE_HERO, CommandType.COM_HERO_HP, -2)
                } else {
                    stat[0] -= 2;
                }

                stat[3] -= 2;
            }
        },
        {
            func: function (stat) {
                if (Utils.getRandomRange(1, 10) < 8) {
                    stat[6] += 4
                    stat[2] = 0
                }
            }
        },
        {
            func: function (stat) {
                stat[3] -= 4;
            }
        },
        {
            func: function (stat) {
                stat[4] -= 4;
            }
        },
        {
            func: function (stat) {
                if (Utils.getRandomRange(1, 10) < 8) {
                    stat[5] -= 4
                    stat[2] = 0
                }
            }
        },
        {
            func: function (stat) {
                stat[3] -= 5;
            }
        },
        {
            func: function (stat) {
                stat[6] -= 5;
            }
        },
        {
            func: function (stat) {
                if (Utils.getRandomRange(1, 10) < 4) {
                    for (let i = 2; i < stat.length; i++) {
                        stat[i] -= Math.round(40 / stat[1])
                    }
                }
            }
        },
        {
            func: function (stat) {
                stat[2] = Math.round(stat[2] / 3);
            }
        },
        {
            func: function (stat, tag, target) {
                if (Utils.getRandomRange(1, 10) < 6) {
                    if (target == 'h') {
                        MessageCenter.SendCustomMessage(MessageType.TYPE_HERO, CommandType.COM_HERO_HP, -Math.round(stat[2] / 3));
                    } else {
                        stat[0] -= Math.round(stat[2] / 3);
                    }
                }
            }
        },
        {
            func: function (stat, tag, target) {
                if (Utils.getRandomRange(1, 10) < 2) {
                    if (target == 'h') {
                        console.log("英雄HP归零，游戏结束");
                        MessageCenter.SendCustomMessage(MessageType.TYPE_HERO, CommandType.COM_HERO_HP, -Hero.Instance.hp)
                    } else {
                        stat[0] = 0;
                    }

                }
            }
        },
        {
            func: function (stat, tag, target) {
                if (target == 'h') {
                    MessageCenter.SendCustomMessage(MessageType.TYPE_HERO, CommandType.COM_HERO_HP, -2)
                    MessageCenter.SendCustomMessage(MessageType.TYPE_HERO, CommandType.COM_HERO_MP, -2)
                } else {
                    stat[0] -= 2;
                    stat[1] -= 2;
                }
            }
        }
    ]
    // 初始化战前属性
    initBattleStat() {
        // 值传递
        this.heroStat = JSON.parse(JSON.stringify(Hero.Instance.abilities));

        // 只有英雄享受属性带来的战时加成
        // 攻击被速度加成
        this.heroStat[2] += Math.round(this.heroStat[6] * 0.1)
        // 防御被体质加成
        this.heroStat[3] += Math.round(this.heroStat[0] * 0.1)
        // 命中被速度和幸运加成
        this.heroStat[4] += (Math.round(this.heroStat[6] * 0.05) + Math.round(this.heroStat[5] * 0.1))

        // map 是浅拷贝 因为目前只有一层，所以直接值赋值。
        // 如果数组里面的元素是对象，则只拷贝对象的引用，这将导致后续改动会反映到原数组上。
        // 宠物每次自动满血出战
        if (Pet.Instance.battlePet.length > 0) {
            this.petStat = Pet.Instance.battlePet.map(e => Array.from(e.stat));
            this.petId = Pet.Instance.battlePet.map(e => e.mid);
        }
        // 怪物属性
        this.monsterStat = Array.from(GameData.Instance.monsterData[this.mid].a);
    }
    // 战斗过程中持续有效的物品
    handleBattleHeroItem() {
        Item.Instance.itemId.forEach((i) => {
            let f = Item.Instance.itemData[i].func;
            if (typeof f == 'function') {
                f(this.heroStat);
            }
        })
    }
    // 渲染更新buff持续时间
    renderBuff(tag, _buff) {
        console.log("更新攻击者的buff图片", tag, _buff);
        let n: Node = null;
        switch (tag) {
            case 'h':
                n = this.heroBuffNode;
                break;
            case 'm':
                n = this.monster0BuffNode;
                break;
            default:
                if (tag == 0) {
                    n = this.pet0BuffNode;
                } else {
                    n = this.pet1BuffNode;
                }
                break;
        }
        for (let i = 0; i < _buff.length; i++) {
            const bid = _buff[i].id;
            let c = n.children[i];
            c.active = true;
            let s = <Sprite>c.getComponent("cc.Sprite");
            s.spriteFrame = GameData.Instance.buffFrames[bid];
        }
    }
    // 处理单只宠物的技能
    // 每一次攻击中的技能触发 (攻击者、防御者)
    handleAllMove(tag, target) {
        // 简化成每次造成伤害前触发技能
        switch (tag) {
            case 'h':
                for (let i = 0; i < Move.Instance.activeMove.length; i++) {
                    // 遍历已拥有的技能
                    if (Hero.Instance.mp > 3) {
                        // 触发已激活的技能
                        let moveid = Move.Instance.activeMove[i];
                        if (typeof GameData.Instance.moveData[moveid] == 'function') {
                            GameData.Instance.moveData[moveid](this.heroStat, tag, target, this.battleQueue);
                            // 统一消耗1~3点蓝
                            MessageCenter.SendCustomMessage(MessageType.TYPE_HERO, CommandType.COM_HERO_MP, -<number>Utils.getRandomRange(1, 3))
                        }
                    }
                }
                break;
            case 'm':
                // 怪物无技能
                break;
            default:
                // 宠物无技能
                break;
        }
    }
    // 更新英雄战时属性，英雄、宠物、怪物血条
    updateStat() {
        let _n = BattleManager.Instance;
        if (!_n.finished) {
            _n.updateHeroStat();
            _n.updatePetStat();
            _n.updateMonsterStat();
            if (Hero.Instance.hp <= 0) {
                _n.deadFunc('h')
            } else if (_n.monsterStat[0] <= 0) {
                _n.deadFunc('m')
            } else {
                for (let i = 0; i < _n.petStat.length; i++) {
                    if (_n.petStat[i][0] <= 0) {
                        _n.deadFunc(i)
                    }
                }
            }
        }
    }
    updateHeroStat() {
        // 左侧状态
        Hero.Instance.updateStat(this.heroStat)
    }
    updatePetStat() {
        // 怪物血条不会更新？
        for (let i = 0; i < this.petStat.length; i++) {
            let id = this.petId[i];
            console.log("宠物属性测试,宠物血条是否更新", this.petStat[i][0], id, GameData.Instance.monsterData[id].b[0])
            let b = <ProgressBar>this.node.getChildByName(`Pet${i}`).children[0].getComponent("cc.ProgressBar");
            b.progress = this.petStat[i][0] / GameData.Instance.monsterData[id].b[0];
        }
    }
    updateMonsterStat() {
        let b = <ProgressBar>this.node.getChildByName("Monster0").children[0].getComponent("cc.ProgressBar");
        b.progress = this.monsterStat[0] / GameData.Instance.monsterData[this.mid].a[0];
    }
    // 伤害计算相关
    ifMiss(s1, s2) {
        let _d = (s1[4] - s2[5] * 0.5) * 2;
        console.log("命中率", _d);
        return _d > 100 ? true : (_d > Utils.getRandomRange(1, 100))
    }
    ifCrit(s1, s2) {
        let _d = (s1[7] - s2[5] * 0.5) * 2;
        console.log("暴击率", _d);
        return _d > 100 ? true : (_d > Utils.getRandomRange(1, 100))
    }
    critDamage(s1, s2) {
        let _d = Math.round(s1[2] * <number>Utils.getRandomRange(13, 20) / 10 + s1[5] * 0.3 + s1[7] / 2 - s2[3] * 0.9 - s2[5] * 0.7)
        console.log("暴击伤害", _d);
        return _d > 0 ? _d : 2;
    }
    normalDamage(s1, s2) {
        let _d = (Math.round(s1[2] * <number>Utils.getRandomRange(8, 12) / 10) - s2[3])
        console.log("正常伤害", _d);
        return _d > 0 ? _d : 1;
    }
    showLabel(s: string) {
        // 显示暴击、闪避等相关文字提示
        let _n = this.node.getChildByName("Result")
        _n.active = true;
        let _l = <Label>_n.getComponent("cc.Label")
        _l.string = s;
        if (!this.finished) {
            this.scheduleOnce(() => {
                _l.string = '';
                _n.active = false;
            }, 0.3)
        }
    }
    dealDamage(_atk, _def, tag, target) {
        // 飘血
        let _d = null;
        // 命中判断
        if (this.ifMiss(_atk, _def)) {
            // 暴击判断
            if (this.ifCrit(_atk, _def)) {
                _d = this.critDamage(_atk, _def);
                // 暴击衰减
                _atk[7] = Math.round(_atk[7] * 0.85)
                this.tips = "暴击";
            } else {
                _d = this.normalDamage(_atk, _def);
                // 暴击补正
                _atk[7] = Math.round(_atk[7] * 1.1)
            }
            // 防御衰减
            _atk[3] = Math.round(_atk[3] * 0.85)
        } else {
            this.tips = "闪避";
            _d = 0;
            // miss 动画
            // 被攻击方幸运衰减
            if (_def[5] > Math.round(_atk[4] * 0.15)) {
                _def[5] -= Math.round(_atk[4] * 0.15)
            }
            // 命中补正
            _atk[4] = Math.round(_atk[4] * 1.15)
        }
        console.log("伤害数值", _d);
        // 检定是否有反伤
        if (false) {

        } else {
            // 动画 _d==0 时意味着防御者闪避了
            this.anim(tag, target, _d);
        }
    }
    // 每次攻击时装载攻击者的buff，到battleQueue
    loadBuff = (tag, target) => {
        console.log("装载buff");
        let _targetBuff = null;
        switch (tag) {
            case 'h':
                _targetBuff = this.heroBuff;
                break;
            case 'm':
                _targetBuff = this.monsterBuff;
                break
            default:
                _targetBuff = this.petBuff[tag];
                break;
        }
        if (typeof _targetBuff == 'object' && _targetBuff.length > 0) {
            // 删掉所有 turn 为 0 的buff
            _targetBuff = _targetBuff.filter(e => e.turn > 0);
            let _tmp = null;
            for (let i = 0; i < _targetBuff.length; i++) {
                _tmp = JSON.parse(JSON.stringify({ ..._targetBuff[i], tag, target }));
                this.battleQueue.push(..._tmp);
                _targetBuff[i].turn--;
            }
        }
    }
    // 处理battleQueue
    handleBattleQueue = (tag, target) => {
        console.log("处理战斗中buff");
        // 其他地方负责添加删除buff，这里负责只调用buff之类的活
        let _stat = null;
        let _buff = null;
        switch (tag) {
            case 'h':
                // 浅拷贝
                _stat = this.heroStat;
                _buff = this.heroBuff;
                break;
            case 'm':
                _stat = this.monsterStat;
                _buff = this.monsterBuff
                break;
            default:
                _stat = this.petStat[tag];
                _buff = this.petBuff[tag];
                break;
        }
        if (!_buff) {
            console.log("buff参数错误");
            return;
        }
        if (typeof _buff == 'object' && _buff.length == 0) {
            return;
        }
        // 更新攻击者身上的buff视图
        this.renderBuff(tag, _buff);
        console.log(this.battleQueue);
        let loop = this.battleQueue.length;
        // id turn tag target
        for (let i = 0; i < loop; i++) {
            if (typeof this.buffData[this.battleQueue[i].id].func == 'function') {
                console.log("buff func ready", _stat, tag, target);
                this.buffData[this.battleQueue[i].id].func(_stat, tag, target, this.battleQueue);
            }
        }
        // 队列持续1回合的buff结算完毕，舍去
        this.battleQueue = this.battleQueue.map(e => e.turn > 1);
        // 队列所有buff回合数减1
        this.battleQueue.forEach(e => e.turn--);
    }

    // 产生攻击序列
    addQueue = () => {
        this.mainTurn++;
        // tag:发起攻击者 'h' 代表英雄 'm' 代表怪物 0 1 代表宠物 s:发起者属性 t:攻击目标
        let speeds = JSON.parse(JSON.stringify([{ tag: 'h', s: this.heroStat, t: 'm' }, { tag: 'm', s: this.monsterStat, t: 'h' }]));
        // 英雄和敌怪必定会攻击1次，活着的出战宠物攻击1次
        for (let i = 0; i < this.petStat.length; i++) {
            speeds.push({ tag: i, s: this.petStat[i], t: 'm' });
            // 宠物在一轮攻击中有40%几率吸引boss的攻击
            if (<number>Utils.getRandomRange(1, 10) < 5) {
                speeds[1].t = i;
            }
        }
        const cmp = function (v1, v2) {
            // 按照速度进行排序
            if (v1.s[6] > v2.s[6]) {
                return 1;
            } else if (v1.s[6] < v2.s[6]) {
                return -1;
            } else {
                return 0;
            }
        }
        speeds = speeds.sort(cmp);
        this.showLabel(`第${this.mainTurn}个主回合`);
        // 速度快的单位可能会多1次出手机会
        let loop = speeds.length
        // 速度快的单位有概率多攻击一次
        for (let i = loop - 1; i > 0; i--) {
            let d = (speeds[i].s[6] - speeds[i - 1].s[6])
            // 速度差>0.4慢速
            if (d < Math.round(speeds[i - 1].s[6] * 0.4)) {
                continue;
            }
            if (<number>Utils.getRandomRange(1, d) > speeds[i - 1].s[6]) {
                speeds.unshift(speeds[i]);
            }
        }
        // 要进行值拷贝
        this.attackQueue = JSON.parse(JSON.stringify(speeds));
        console.log(this.attackQueue);
    }
    // 死亡处理
    deadFunc = (person) => {
        switch (person) {
            case 'h':
                if (Hero.Instance.hp <= 0) {
                    this.finished = true
                    this.showLabel("战斗失败，玩家已死亡");
                    // 显示 再来一局 按钮
                    (<Label>this.node.getChildByName("Result").children[1].getComponentInChildren("cc.Label")).string = "重新开始";
                    this.node.getChildByName("Result").children[1].active = true;
                }
                break;
            case 'm':
                if (this.monsterStat[0] <= 0) {
                    console.log("怪物已死亡");
                    this.finished = true;
                    if (Map.Instance.cur_map_floor == 3 && Map.Instance.cur_hero_pos == 2) {
                        this.showLabel("你打败了最终BOSS");
                        // 再来一局 按钮
                        (<Label>this.node.getChildByName("Result").children[0].getComponentInChildren("cc.Label")).string = "再来一局";
                        this.node.getChildByName("Result").children[0].active = true;
                        return;
                    } else {
                        this.showLabel("战斗胜利")
                    }
                    // 奖励结算
                    if (Pet.Instance.pet.length < 4) {
                        // 两个按钮显示出来，询问玩家是否捕捉战败宠物
                        this.node.getChildByName("Result").children[0].active = true;
                        (<Label>this.node.getChildByName("Result").children[1].getComponentInChildren("cc.Label")).string = "捕捉";
                        this.node.getChildByName("Result").children[1].active = true;
                        (<Label>this.node.getChildByName("Result").children[1].getComponentInChildren("cc.Label")).string = "放生";
                    } else {
                        // 清除战时的数据
                        this.initData();
                        // 直接获胜
                        this.handleWin();
                    }
                    // 战后延迟物品处理,判断是否有该怪物的悬赏令生效
                    Item.Instance.checkItem();
                }
                break;
            default:
                if (typeof person == 'number' && typeof this.petStat[person] == 'object' && this.petStat[person][0] <= 0) {
                    this.showLabel("宠物死亡" + person);
                    console.log("宠物死亡")
                    // 将宠物的行动移出 attackQueue
                    // console.log(this.attackQueue);
                    // 移除宠物的行动
                    this.attackQueue = this.attackQueue.filter(e => e.tag != person);
                    // console.log(this.attackQueue);
                    // 原本攻击宠物的怪物攻击序列，改为攻击英雄
                    this.attackQueue = this.attackQueue.map(e => {
                        if (e.t == person) {
                            e.t = 'h';
                        }
                        // if (person == 0 && this.petStat.length == 2) {
                        //     // 如果死的是第一只宠物而且第二只宠物也出战，那么第二只宠物的下标更新为0
                        //     if (e.t == 1) {
                        //         e.t = 0;
                        //     }
                        //     if (e.tag == 1) {
                        //         e.tag = 0;
                        //     }
                        // }
                        return e;
                    })
                    // console.log(this.attackQueue);
                    // 隐藏战斗中阵亡的宠物头像和血条
                    this.node.getChildByName(`Pet${person}`).active = false;
                    // 移出当前宠物状态
                    // this.petStat.splice(person, 1);
                    // 宠物身上的 buff 也移除掉
                    // this.petBuff.splice(person, 1);
                    Pet.Instance.lostPet(this.petId[person]);
                    // this.petId.splice(person, 1);
                }
        }
    }
    // 游戏战斗逻辑
    battleHandler(mid) {
        // 显示战斗界面
        this.node.active = true;
        // 敌怪id
        this.mid = mid;
        console.log("战斗", GameData.Instance.monsterTips[mid]);
        // 关闭大/小地图显示
        // 如果MiniMap节点未启用，组件为初始化，程序运行到MiniMap.Instance会停止响应
        if (MiniMap.Instance.areaMapPos > -1) {
            MiniMap.Instance.node.active = false;
        } else {
            Map.Instance.node.active = false;
        }
        if (!mid || mid >= 43 || mid < 0) {
            console.log("战斗，参数错误");
            return;
        }
        // 初始化战斗中的属性
        this.initBattleStat();

        // 渲染战时英雄图片
        let heroNode = this.node.getChildByName("Hero");
        heroNode.active = true;
        (<Sprite>heroNode.getComponent("cc.Sprite")).spriteFrame = GameData.Instance.heroFrames[Hero.Instance.type];
        // 如果有buff还要加载buff图片

        // 渲染战时宠物及buff图片
        for (let i = 0; i < this.petId.length; i++) {
            const id = this.petId[i];
            let _pn = this.node.getChildByName(`Pet${i}`);
            _pn.active = true;
            (<Sprite>_pn.getComponent("cc.Sprite")).spriteFrame = GameData.Instance.monsterFrames[id];
        }

        // 渲染战时怪物及buff图片
        let monsterNode = <Node>this.node.getChildByName(`Monster0`);
        monsterNode.active = true;
        (<Sprite>monsterNode.getComponent("cc.Sprite")).spriteFrame = GameData.Instance.monsterFrames[mid];
        console.log(this.heroStat);

        Item.Instance.itemId.forEach(v => {
            // 战前生效一次的属性加成物品
            if (typeof (Item.Instance.itemData[v].a) == 'object') {
                for (let i = 0; i < Item.Instance.itemData[v].a.length; i++) {
                    this.heroStat[i] += Item.Instance.itemData[v].a[i];
                }
            }
            // 战斗前赋予buff的物品
            if (typeof (Item.Instance.itemData[v].buff) == 'function') {
                // 战前获得buff
                Item.Instance.itemData[v].buff()
            }
        });
        console.log(this.heroStat);
        // 更新战斗时的各项属性
        this.updateStat()
        // 开始攻击
        this.atk()
    }
    // 伤害结算
    calculateDamage(tag, target) {
        if (this.finished) {
            console.log("战斗结束")
            return;
        }
        let _atk = null, _def = null;
        switch (tag) {
            case 'h':
                _atk = this.heroStat;
                break;
            case 'm':
                _atk = this.monsterStat;
                break;
            default:
                _atk = this.petStat[tag]
                if (_atk[0] <= 0) {
                    console.log("宠物已死亡", tag);
                    return;
                }
                break;
        }
        switch (target) {
            case 'h':
                _def = this.heroStat;
                break;
            case 'm':
                _def = this.monsterStat;
                break;
            default:
                _def = this.petStat[target]
                if (_atk[0] <= 0) {
                    console.log("宠物死亡，改为攻击英雄", tag);
                    _def = this.heroStat;
                }
                break;
        }

        if (!_atk || !_def) {
            console.log(_atk, _def, "伤害计算错误");
            return;
        }
        console.log(_atk, _def, "结算技能前")
        // 处理攻击者的技能
        this.handleAllMove(tag, target);
        this.updateStat();
        console.log(_atk, _def, "结算技能后")
        // 装载所有人的buff buff会在每次行动时消耗一层
        this.loadBuff(tag, target);
        // 行动之前，传入攻击方和被攻击方，只结算攻击方buff，因为攻击方的buff可能会给防御方施加debuff
        this.handleBattleQueue(tag, target);
        this.updateStat()
        console.log(_atk, _def, "结算buff后", this.monsterBuff);
        this.dealDamage(_atk, _def, tag, target)
        // 在攻击动画的回调里更新血条
        console.log(_atk, _def, "结算战斗伤害后")
    }
    atk() {
        let _c = BattleManager.Instance;
        if (_c.finished == false) {
            // 每一次攻击，更新英雄、宠物、怪物血条蓝条
            if (_c.attackQueue.length == 0 && Hero.Instance.hp > 0) {
                // 战时持续生效的物品，在每个攻击主回合生效一次，因为会生成buff，所以需要放在buff前面
                _c.handleBattleHeroItem();
                // 一次攻击主回合，依据速度决定出手顺序
                _c.addQueue()
            };
            // 依次出手攻击
            let t = _c.attackQueue.pop()
            if (t) {
                console.log(t.tag, "开始攻击", t.t)
                _c.calculateDamage(t.tag, t.t)
            }
        }
    }
    // 播放 1s 战斗过程动画 t 攻击者 m 防御者 l 攻击方对防御方打出的伤害值 r 攻击方受到反弹伤害
    anim(t, m, l, r?) {
        console.log(t, m, l);
        let atk = this.node.getChildByName("Attack");
        // 记录剑气的原始方向
        atk.scale = new Vec3(1, 1, 1);
        let atkNode = null;
        switch (t) {
            case 'h':
                atkNode = this.node.getChildByName("Hero");
                break;
            case 'm':
                atkNode = <Node>this.node.getChildByName("Monster0");
                // 如果是怪物攻击，则剑气方向在X轴翻转
                atk.scale = new Vec3(-1, 1, 1);
                break;
            default:
                atkNode = this.node.getChildByName(`Pet${t}`);
                break;
        }
        // 将剑气的初始位置设置为攻击者的位置
        atk.setPosition(atkNode.position);

        let def = this.node.getChildByName("Defense");
        let defNode = null;;
        switch (m) {
            case 'h':
                defNode = this.node.getChildByName('Hero');
                break;
            case 'm':
                defNode = this.node.getChildByName('Monster0');
                break;
            default:
                defNode = this.node.getChildByName(`Pet${m}`);
                break;
        }
        // 将受击动画所在的节点的位置设置为防御者的位置
        def.setPosition(defNode.position)
        // 计算剑芒发射的角度
        let zAngle = 180 * Math.atan((defNode.position.y - atkNode.position.y) / (defNode.position.x - atkNode.position.x)) / Math.PI
        // console.log("剑芒角度", zAngle);
        atk.setRotationFromEuler(0, 0, zAngle);
        const atkCallback = () => {
            if (r) {
                // 如果有反伤，则拿到攻击者的受伤数值节点，激活，显示反伤结果
                let atkDamage = atkNode.getChildByName("Damage");
                atkDamage.active = true;
                let _label = <Label>atkDamage.getComponent("cc.Label");
                _label.string = "-" + l;
                // 受伤的文字数值节点会有变大变小的缓动动画
                new Tween(atkDamage)
                    .to(0.2, { scale: new Vec3(2, 2, 1) }, { easing: 'linear' })
                    .to(0.2, { scale: new Vec3(0.5, 0.5, 1) }, { easing: 'linear' })
                    .call(() => {
                        console.log("反伤动画播放完毕");
                        if (t == 'h') {
                            MessageCenter.SendCustomMessage(MessageType.TYPE_HERO, CommandType.COM_HERO_HP, -r)
                        } else if (t == 'm') {
                            this.monsterStat[0] -= r;
                        } else {
                            this.petStat[t][0] -= r;
                        }
                        _label.string = '';
                        atkDamage.active = false;
                        this.updateStat()
                    })
                    .start()
            }
            if (l == 0) {
                // 防御者闪避了攻击
                this.showLabel('闪避');
                // 防御者会有晃动一下的动画
                new Tween(defNode)
                    .by(0.2, { position: new Vec3(-50, 50, 0) }, { easing: 'linear' })
                    .by(0.2, { position: new Vec3(50, -50, 0) }, { easing: 'linear' })
                    .call(() => {
                        console.log("闪避动画播放完毕");
                        this.updateStat()
                        this.atk()
                    })
                    .start()
            } else {
                // 防御者受伤 def 受击GIF动画
                def.active = true;
                // 显示防御者的飘血数值节点
                let defDamage = defNode.getChildByName("Damage");
                defDamage.active = true;
                // 显示受伤数值并有一个变大变小缓动动画
                let _label = <Label>defDamage.getComponent("cc.Label");
                _label.string = "-" + l;
                new Tween(defDamage)
                    .to(0.2, { scale: new Vec3(2, 2, 1) }, { easing: 'linear' })
                    .to(0.2, { scale: new Vec3(0.5, 0.5, 1) }, { easing: 'linear' })
                    .call(() => {
                        console.log("飘血动画播放完毕");
                        if (m == 'h') {
                            MessageCenter.SendCustomMessage(MessageType.TYPE_HERO, CommandType.COM_HERO_HP, -l)
                        } else if (m == 'm') {
                            this.monsterStat[0] -= l;
                        } else {
                            this.petStat[m][0] -= l;
                        }
                        _label.string = '';
                        defDamage.active = false;
                        def.active = false;
                        this.updateStat()
                        this.atk()
                    })
                    .start()
            }
        }
        // 调用普通攻击组件中的播放动画函数，传参为防御者的位置、攻击完后执行的回调
        (<Attack>atk.getComponent("Attack")).play(defNode.position, atkCallback);
    }
    // 处理战后奖励结算
    handleWin = () => {
        let _exp = Math.round(GameData.Instance.monsterData[this.mid].e + Math.max(0, this.heroStat[1] * 0.3));
        // 渲染英雄属性状态和血条蓝条经验条
        console.log(Hero.Instance.abilities, this.heroStat);
        this.reset();
        // 更新经验条及金币
        Hero.Instance.exp += _exp;
        Hero.Instance.gold += (GameData.Instance.monsterData[this.mid].g);
    }
    // 处理可捕捉击败的宠物的两个按钮
    renderCatchScreen(e, d) {
        if (Hero.Instance.hp <= 0) {
            // 清除战时的数据
            let _n = this.node.getChildByName("Result");
            _n.children[1].active = false;
            // 隐藏捕捉界面
            _n.active = false;
            // 主回合归零
            this.mainTurn = 0;
            // 战斗队列清零
            this.battleQueue = [];
            // 关闭战斗时宠物的显示
            for (let i = 0; i < this.petId.length; i++) {
                let _pn = this.node.getChildByName(`Pet${i}`);
                _pn.active = false;
            }
            this.initData();
            // 重来一局
            UIManager.Instance.gameOver(false);
            return;
        }
        let _exp = Math.round(GameData.Instance.monsterData[this.mid].e + Math.max(0, this.heroStat[1] * 0.3));
        // 监听按钮的点击事件
        if (d == 'true') {
            // 在最后BOSS层发生战斗，战斗结束
            if (Map.Instance.cur_map_floor == 3) {
                UIManager.Instance.gameOver(true);
            } else {
                console.log("开始捕捉")
                this.reset()
                Pet.Instance.catchPet(this.mid);
                // 更新经验条及金币
                Hero.Instance.exp += (_exp / 2);
                Hero.Instance.gold += (GameData.Instance.monsterData[this.mid].g / 2);
            }
        } else if (d == 'false') {
            console.log("决定放生");
            this.reset()
            // 更新经验条及金币
            Hero.Instance.exp += (_exp);
            Hero.Instance.gold += (GameData.Instance.monsterData[this.mid].g);
        }
        // 清除战时的数据
        this.initData();
    }
    reset(dontGoMap?) {
        let _n = this.node.getChildByName("Result");
        _n.children[0].active = false;
        _n.children[1].active = false;
        // 隐藏捕捉界面
        _n.active = false;
        // 主回合归零
        this.mainTurn = 0;
        // 战斗队列清零
        this.battleQueue = [];

        // 关闭战斗时宠物的显示
        for (let i = 0; i < this.petId.length; i++) {
            let _pn = this.node.getChildByName(`Pet${i}`);
            _pn.active = false;
        }

        // 关闭 battle 场景
        this.node.active = false;
        // 更新回英雄的正常属性
        Hero.Instance.updateStat();
        // 如果处于小地图，则返回小地图；否则返回大地图
        if (MiniMap.Instance.areaMapPos > -1) {
            MiniMap.Instance.node.active = true;
        } else {
            Map.Instance.node.active = true;
        }
    }
}

/**
 * [1] Class member could be defined like this.
 * [2] Use `property` decorator if your want the member to be serializable.
 * [3] Your initialization goes here.
 * [4] Your update function goes here.
 *
 * Learn more about scripting: https://docs.cocos.com/creator/3.3/manual/zh/scripting/
 * Learn more about CCClass: https://docs.cocos.com/creator/3.3/manual/zh/scripting/ccclass.html
 * Learn more about life-cycle callbacks: https://docs.cocos.com/creator/3.3/manual/zh/scripting/life-cycle-callbacks.html
 */
